<!DOCTYPE html>
<html>
<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by an Apache 2.0 License.
See the COPYING file for details.
-->
<!-- Author:  attila@google.com (Attila Bodis) -->
<head>
  <title>Closure Unit Tests - goog.Disposable</title>
  <script src="../base.js"></script>
  <script>
    goog.require('goog.Disposable');
    goog.require('goog.testing.jsunit');
  </script>
</head>
<body>
  <div id="someElement">Hello!</div>
  <script>
    var d1, d2;

    // Sample subclass of goog.Disposable.

    function DisposableTest() {
      goog.Disposable.call(this);
      this.element = document.getElementById('someElement');
    }
    goog.inherits(DisposableTest, goog.Disposable);

    DisposableTest.prototype.disposeInternal = function() {
      delete this.element;
    };

    // Class that doesn't inherit from goog.Disposable, but implements the
    // disposable interface via duck typing.

    function DisposableDuck() {
      this.element = document.getElementById('someElement');
    }

    DisposableDuck.prototype.dispose = function() {
      delete this.element;
    };

    // Class which calls dispose recursively.

    function RecursiveDisposable() {
      this.disposedCount = 0;
    }
    goog.inherits(RecursiveDisposable, goog.Disposable);

    RecursiveDisposable.prototype.disposeInternal = function() {
      ++this.disposedCount;
      assertEquals('Disposed too many times', 1, this.disposedCount);
      this.dispose();
    };

    // Test methods.

    function setUp() {
      d1 = new goog.Disposable();
      d2 = new DisposableTest();
    }

    function tearDown() {
      d1.dispose();
      d2.dispose();
    }

    function testConstructor() {
      assertFalse(d1.isDisposed());
      assertFalse(d2.isDisposed());
      assertEquals(document.getElementById('someElement'), d2.element);
    }

    function testDispose() {
      assertFalse(d1.isDisposed());
      d1.dispose();
      assertTrue('goog.Disposable instance should have been disposed of',
          d1.isDisposed());

      assertFalse(d2.isDisposed());
      d2.dispose();
      assertTrue('goog.DisposableTest instance should have been disposed of',
          d2.isDisposed());
    }

    function testDisposeInternal() {
      assertNotUndefined(d2.element);
      d2.dispose();
      assertUndefined('goog.DisposableTest.prototype.disposeInternal should ' +
          'have deleted the element reference', d2.element);
    }

    function testDisposeAgain() {
      d2.dispose();
      assertUndefined('goog.DisposableTest.prototype.disposeInternal should ' +
          'have deleted the element reference', d2.element);
      // Manually reset the element to a non-null value, and call dispose().
      // Because the object is already marked disposed, disposeInternal won't
      // be called again.
      d2.element = document.getElementById('someElement');
      d2.dispose();
      assertNotUndefined('disposeInternal should not be called again if the ' +
          'object has already been marked disposed', d2.element);
    }

    function testDisposeWorksRecursively() {
      new RecursiveDisposable().dispose();
    }

    function testStaticDispose() {
      assertFalse(d1.isDisposed());
      goog.dispose(d1);
      assertTrue('goog.Disposable instance should have been disposed of',
          d1.isDisposed());

      assertFalse(d2.isDisposed());
      goog.dispose(d2);
      assertTrue('goog.DisposableTest instance should have been disposed of',
          d2.isDisposed());

      var duck = new DisposableDuck();
      assertNotUndefined(duck.element);
      goog.dispose(duck);
      assertUndefined('goog.dispose should have disposed of object that ' +
          'implements the disposable interface', duck.element);
    }

    function testStaticDisposeOnNonDisposableType() {
      // Call goog.dispose() with various types and make sure no errors are
      // thrown.
      goog.dispose(true);
      goog.dispose(false);
      goog.dispose(null);
      goog.dispose(undefined);
      goog.dispose('');
      goog.dispose([]);
      goog.dispose({});

      function A() {}
      goog.dispose(new A());
    }
  </script>
</body>
</html>
